package com.polaris.live.utils.zego.core

import android.view.ViewGroup
import androidx.core.os.bundleOf
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.hjq.language.MultiLanguages
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.StructUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.EventConst
import com.polaris.live.resp.bean.PreGameBean
import com.polaris.live.translation.R.string
import com.polaris.live.utils.image.ImageUtils
import com.polaris.live.utils.postEvent
import com.polaris.live.utils.zego.LiveEngineManage
import com.polaris.live.utils.zego.listener.PreGameListener
import im.zego.minigameengine.ZegoGameEngineError
import im.zego.minigameengine.ZegoGameLanguage
import im.zego.minigameengine.ZegoGameMode
import im.zego.minigameengine.ZegoGameTaxType
import im.zego.minigameengine.ZegoGameUserInfo
import im.zego.minigameengine.ZegoMiniGameEngine
import im.zego.minigameengine.ZegoStartGameConfig
import im.zego.minigameengine.ZegoUserSeatInfo
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap

/**
 * 即构小游戏控制
 * @author Created by 天晴 on 2024/3/13 19:42
 * @since 1.0.0
 **/
class MiniGameEngineHandler(
    private val appId: Long,
    private val tokenHandler: ZegoTokenHandler,
) {

    private val engine = ZegoMiniGameEngine.getInstance()

    //预加载过的游戏
    private val preGameMap = ConcurrentHashMap<String, PreGameBean>()

    /**
     * 获取游戏引擎
     */
    fun getEngine(): ZegoMiniGameEngine {
        return engine
    }

    /**
     * 初始化引擎
     */
    fun initEngIne(block: ((errorCode: Int, obj: String) -> Unit)? = null) {
        if (engine.isInit) {
            block?.invoke(0, "")

            LogExt.logI(LiveEngineManage.TAG_GAME, "initEngIne initialized")
        } else {
            CoroutineScopeManager.defaultScope.launch {
                val token = tokenHandler.getToken(null)
                val user = UserManager.getUser()
                val userId = "${user.userId}"
                val userName = "${user.nickname}"
                val userAvatar = ImageUtils.imgPathSmall(user.avatar)
                val userInfo = ZegoGameUserInfo(userId, userName, userAvatar)

                engine.init(appId, token, userInfo) { errorCode, obj ->
                    block?.invoke(errorCode, obj)
                    setGameLanguage()

                    LogExt.logI(
                        LiveEngineManage.TAG_GAME,
                        "initEngIne success: errorCode = $errorCode"
                    )
                }
            }
        }
    }

    private fun setGameLanguage() {
        val la = MultiLanguages.getAppLanguage()
        val language = when (la.language) {
            "zh" -> {
                if (la.country.contains("CN")) {
                    ZegoGameLanguage.zh_CN
                } else if (la.country.contains("HK") || la.country.contains("TW")
                ) {
                    ZegoGameLanguage.zh_TW
                } else {
                    ZegoGameLanguage.zh_CN
                }
            }

            "en" -> {
                ZegoGameLanguage.en
            }

            "ar" -> {
                ZegoGameLanguage.ar
            }

            "pt" -> {
                ZegoGameLanguage.pt
            }

            "ja" -> {
                ZegoGameLanguage.ja
            }

            "ko" -> {
                ZegoGameLanguage.ko
            }

            "es" -> {
                ZegoGameLanguage.es
            }

            "ms" -> {
                ZegoGameLanguage.ms
            }

            "tr" -> {
                ZegoGameLanguage.tr
            }

            "hi" -> {
                ZegoGameLanguage.hi
            }

            "vi" -> {
                ZegoGameLanguage.vi
            }

            else -> {
                ZegoGameLanguage.en
            }
        }
        engine.setGameLanguage(ZegoGameLanguage.en)
    }

    /**
     * 反加载引擎
     */
    fun unInit() {
        engine.unInit()
    }

    /**
     * 更新token
     */
    fun updateToken(token: String) {
        engine.updateToken(token)

        LogExt.logI(LiveEngineManage.TAG_GAME, "updateToken: token = $token")
    }

    fun preloadGame(
        gameId: String,
        listener: PreGameListener?,
    ) {
        var preGame = preGameMap[gameId]
        if (preGame == null) {
            preGame = PreGameBean(gameId, StructUtils.newSaleSet(), -1, 0).apply {
                listener?.let {
                    preGameList.add(it)
                }
            }
            preGameMap[gameId] = preGame
            LogExt.logI(LiveEngineManage.TAG_GAME, "gameId:$gameId   new PreGameBean----")
        } else {
            if (preGame.errorCode == 0 && preGame.progress == 100) {
                listener?.callback(0, 100)
            } else {
                listener?.let {
                    LogExt.logI(LiveEngineManage.TAG_GAME, "gameId:$gameId    add PreGameListener")
                    preGame.preGameList.add(it)
                }
            }
        }
        if (preGame.errorCode != 0) {
            preGame(gameId)
        }
    }

    private fun preGame(gameId: String) {
        postEvent("preLoad", gameId)

        LogExt.logI(LiveEngineManage.TAG_GAME, "gameId:$gameId    preGame------")

        engine.preloadGame(gameId) { code, p ->
            preGameMap[gameId]?.apply {
                errorCode = code
                progress = p
                preGameList.forEach {
                    it.callback(code, p)
                }
                if ((code == 0 && p == 100) || code != 0) {
                    preGameMap.remove(gameId)
                    LogExt.logI(
                        LiveEngineManage.TAG_GAME,
                        "gameId:$gameId    preGameList------clear"
                    )
                }
            }

            if (code != 0 || p == 100) {
                postEvent("preLoadProgress", gameId, mapOf("code" to code, "progress" to p))
            }
        }
    }

    fun removePreGameListener(listener: PreGameListener) {
        preGameMap.forEach { (_, value) ->
            value.preGameList.remove(listener)
        }
    }

    /**
     * 加载游戏
     */
    fun loadGame(
        roomId: String,
        gameId: String,
        gameContainer: ViewGroup,
        callback: ((errorCode: Int) -> Unit)? = null,
    ) {
        postEvent("gameLoad", gameId)

        LogExt.logI(LiveEngineManage.TAG_GAME, "loadGame start")

        try {
            val isCustomPlay = false
            val gameConfig = HashMap<String, Any>()
            gameConfig[ZegoMiniGameEngine.GAME_CONFIG_ROOM_ID] = roomId
            gameConfig[ZegoMiniGameEngine.GAME_CONFIG_CUSTOM_PLAY_SOUND] = isCustomPlay
            gameConfig[ZegoMiniGameEngine.MIN_GAME_COIN] = 0L
            gameConfig["specificConfig"] = mapOf("moneyMode" to 0)

            engine.setGameContainer(gameContainer)
            engine.loadGame(
                gameId,
                ZegoGameMode.ZegoGameModeHostsGame, gameConfig
            ) { errorCode, obj ->
                if (ZegoGameEngineError.SUCCESS == errorCode ||
                    ZegoGameEngineError.ERROR_GAME_ALREADY_LOADED == errorCode
                ) {
                    // 游戏正常加载
                } else {
                    //游戏异常
                }
                callback?.invoke(errorCode)

                LogExt.logI(
                    LiveEngineManage.TAG_GAME,
                    "loadGame success: errorCode = $errorCode, obj = $obj"
                )

                postEvent("gameLoadProgress", gameId, mapOf("code" to errorCode, "ext" to obj))
            }
        } catch (e: Exception) {
            ToastGravity.showGravity(string.game_load_error)

            LogExt.logE(LiveEngineManage.TAG_GAME, "loadGame error", e)

            postEvent("gameLoadError", gameId, mapOf("error" to e.message))
        }
    }

    /**
     * 开始游戏
     */
    fun startGame(gameId: String?, selectUserIDList: List<String>, back: (code: Int) -> Unit) {
        postEvent("gameStart", gameId ?: "unknown")

        val userList: MutableList<ZegoUserSeatInfo> = ArrayList()
        for ((seatIndex, userID) in selectUserIDList.withIndex()) {
            userList.add(ZegoUserSeatInfo(userID, seatIndex))
        }
        val gameConfig = ZegoStartGameConfig()
        gameConfig.taxType = ZegoGameTaxType.ZegoGameTaxTypeBetCoin
        gameConfig.taxRate = 0
        gameConfig.minGameCoin = 0
        gameConfig.timeOut = 15
        engine.startGame(gameConfig, userList, null) { errorCode, obj ->
            back.invoke(errorCode)

            LogExt.logI(LiveEngineManage.TAG_GAME, "startGame: errorCode = $errorCode, obj = $obj")

            postEvent("gameStartProgress", gameId ?: "unknown", mapOf("code" to errorCode, "ext" to obj))
        }
    }

    /**
     * 反加载游戏
     */
    fun unloadGame(forceQuit: Boolean = false) {
        engine.unloadGame(forceQuit)

        LogExt.logI(LiveEngineManage.TAG_GAME, "unloadGame: forceQuit = $forceQuit")

        postEvent("gameUnload", "unknown", mapOf("forceQuit" to forceQuit))
    }

    private fun postEvent(event: String, gameId: String, map: Map<String, Any?> = emptyMap()) {
        try {
            val bundle = bundleOf("event" to event, "gameId" to gameId)
            map.forEach { (key, value) ->
                if (value != null) {
                    bundle.putString(key, value.toString())
                }
            }

            Firebase.analytics.postEvent(EventConst.ZEGO_GAME_LOAD_EVENT, bundle)
        } catch (_: Throwable) {
        }
    }
}